/**************************************************************************//**
 * @item     CosyOS-III 例程（服务应用）
 * @file     comp_usart.c
 * @brief    综合应用_串口
 * @details  本例程模拟了在多个任务和中断中，均有发送项要通过串口1发送至外部设备
             的复杂应用，结合定时中断和定时查询，实现了自动控制发送分包间隔时间，
             及接收解析处理。
 * @note     发送类别包括：
             1、用事件标志组 实现 非并发事件发送；
             2、用计数信号量 实现 并发事件发送；
             3、用消息  队列 实现 并发消息发送。
 * @note     本例程仅以 STM32-HAL库 的应用为例，其它情形请用户自行做出调整。
 * @author   迟凯峰
 * @version  V1.0.0
 * @date     2025.11.01
 ******************************************************************************/

#if 1 /* 编译开关 */


#define PENDSV_FIFO_FLAG  2 // 定时服务为中断挂起服务，选择 FIFO服务 或 FLAG服务（1：FIFO服务，2：FLAG服务）
#define pack_uart1_send  30 // 串口1发送分包间隔时间（单位：ms）
#define pack_uart1_recv  20 // 串口1接收分包提前解析时间（单位：ms）
                            // 假定 接收分包间隔时间为30ms，定时20ms提前解析，并在30ms内完成解析

#include "CosyOS.H"
#include <string.h>

#define tmid_uart1_send   0 // 定时查询定时器ID for 串口1发送
#define tmid_uart1_recv   0 // 定时中断定时器ID for 串口1接收解析

extern  UART_HandleTypeDef huart1;

static struct
{
    bool err;
    char *p;
    char buff[32];
}uart1_recv; // for 串口1接收

uExternFlagGroup
(
    uart1_send,
    uDefFlagBit(ack1);
    uDefFlagBit(ack2);
    uDefFlagBit(ack3);
    uDefFlagBit(ack4);
    uDefFlagBit(send1);
    uDefFlagBit(send2);
    uDefFlagBit(send3);
    uDefFlagBit(send4);
    uDefFlagBit(send5);
    uDefFlagBit(send6);
    uDefVoidBits(6);
);
static uCreateFlagGroup(uart1_send); // 声明并创建事件标志组 for 串口1非并发事件发送
static uCreateSem(uart1_sem, 0, ~0); // 创建计数信号量 for 串口1并发事件发送
static uCreateQueue_Static(uart1_queue, 0, 10); // 创建消息队列 for 串口1并发消息发送


/*
 * 定时服务 采用 FLAG服务
 */
#if (PENDSV_FIFO_FLAG != 1)
static bool flag_uart1_recv = false;
static bool flag_uart1_send = false;
/**
 * \brief    滴答钩子
 * \details  依次查询各个标志，为真就清除标志，而后调用相应服务。
 * @note     此处应调用前缀为“t”的滴答服务。
 */
void tick_hook(void) MCUCFG_OSIT_ATTRIBUTE
{
    if(flag_uart1_send){
        flag_uart1_send = false;
        tTimQry_ms(tmid_uart1_send, pack_uart1_send);
    }
    if(flag_uart1_recv){
        flag_uart1_recv = false;
        tTimInt_ms(tmid_uart1_recv, pack_uart1_recv);
    }
}
#endif


/** 串口发送完成回调 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        /* 用定时查询来控制发送分包间隔时间 */
        #if (PENDSV_FIFO_FLAG == 1) /* FIFO服务 */
        iTimQry_ms(tmid_uart1_send, pack_uart1_send);
        #else /* FLAG服务 */// 定时服务仅时间关键，无需触发PendSV，而是在系统滴答中调用并执行服务。
        flag_uart1_send = true;
        #endif
    }
}

/** 串口接收完成回调 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1){
        if(!uart1_recv.err){
            if(uart1_recv.p - uart1_recv.buff + 1 < sizeof(uart1_recv.buff)){
                uart1_recv.p++;
            }
            else{
                uart1_recv.err = true;
                uart1_recv.p = uart1_recv.buff;
            }
        }
        else{
            uart1_recv.p = uart1_recv.buff;
        }
        HAL_UART_Receive_DMA(&huart1, (uint8_t *)uart1_recv.p, 1);
        /* 用定时中断来控制接收分包间隔时间，并提前解析（在下一包数据到来之前完成解析）*/
        #if (PENDSV_FIFO_FLAG == 1) /* FIFO服务 */
        iTimInt_ms(tmid_uart1_recv, pack_uart1_recv);
        #else /* FLAG服务 */// 定时服务仅时间关键，无需触发PendSV，而是在系统滴答中调用并执行服务。
        flag_uart1_recv = true;
        #endif
    }
}

/**
 * \brief    串口1接收任务（定时中断任务）
 * \details  负责串口1接收数据的解析。
 */
uCreateTask_TimInt
(
    tmid_uart1_recv, false,
    task_uart1_recv, 5, 384, 0, 0
)
{
    while(1){
        if(!uart1_recv.err){
            /* 接收解析 BEGIN *///uart1_recv.p - uart1_recv.buff 为数据包有效长度
            *uart1_recv.p = '\0';
                 if(!strcmp(uart1_recv.buff, "hello1\r\n")){
                uSetFlagBit(uart1_send, ack1);
            }
            else if(!strcmp(uart1_recv.buff, "hello2\r\n")){
                uSetFlagBit(uart1_send, ack2);
            }
            else if(!strcmp(uart1_recv.buff, "hello3\r\n")){
                uSetFlagBit(uart1_send, ack3);
            }
            else if(!strcmp(uart1_recv.buff, "hello4\r\n")){
                uSetFlagBit(uart1_send, ack4);
            }
            /* 接收解析 END */
        }
        else{
            uart1_recv.err = false;
        }
        uart1_recv.p = uart1_recv.buff;
        HAL_UART_Receive_DMA(&huart1, (uint8_t *)uart1_recv.p, 1);
        uSuspendTasking();
    }
}

/**
 * \brief    串口1发送任务（定时查询任务）
 * \details  统一处理所有发送项，按自定义优先级依次查询并发送各发送项。
 * \note     事件标志组：依次查询各个标志位，为真就清除标志位而后发送。
 * \note     计数信号量：获取并立即返回结果，为真就发送。
 * \note     消息  队列：接收并立即返回结果，为真就发送。
 */
uCreateTask_TimQry
(
    tmid_uart1_send, tQueryFlagGroup(uart1_send) || uart1_sem.counter || uart1_queue.counter, false,
    task_uart1_send, 4, 384, 0, 0
)
{
    while(1){
        char *s;
        
             if(uart1_send.ack1){
            uClearFlagBit(uart1_send, ack1);
            s = "ack1\r\n";
        }
        else if(uart1_send.ack2){
            uClearFlagBit(uart1_send, ack2);
            s = "ack2\r\n";
        }
        else if(uart1_send.ack3){
            uClearFlagBit(uart1_send, ack3);
            s = "ack3\r\n";
        }
        else if(uart1_send.ack4){
            uClearFlagBit(uart1_send, ack4);
            s = "ack4\r\n";
        }
        else if(uTakeSem(uart1_sem, 0)){
            s = "warning !!!\r\n";
        }
        else{
            s = uRecvMsg(uart1_queue, 0);
            if(s);
            else if(uart1_send.send1){
                uClearFlagBit(uart1_send, send1);
                s = "send1\r\n";
            }
            else if(uart1_send.send2){
                uClearFlagBit(uart1_send, send2);
                s = "send2\r\n";
            }
            else if(uart1_send.send3){
                uClearFlagBit(uart1_send, send3);
                s = "send3\r\n";
            }
            else if(uart1_send.send4){
                uClearFlagBit(uart1_send, send4);
                s = "send4\r\n";
            }
            else if(uart1_send.send5){
                uClearFlagBit(uart1_send, send5);
                s = "send5\r\n";
            }
            else if(uart1_send.send6){
                uClearFlagBit(uart1_send, send6);
                s = "send6\r\n";
            }
        }
        
        HAL_UART_Transmit_DMA(&huart1, (uint8_t *)s, strlen(s));
        uSuspendTasking();
    }
}

/**
 * \brief    task_1
 * \details  用来模拟串口1的发送源。
 */
uCreateTask(task_1, 1, 384, 0, 0)
{
    while(1){
        uSetFlagBit(uart1_send, send1); // 非并发事件发送
        uDelay_ms(500);
        uSendMsg(uart1_queue, "queue msg 1\r\n"); // 并发消息发送
        uDelay_ms(500);
    }
}

/**
 * \brief    task_2
 * \details  用来模拟串口1的发送源。
 */
uCreateTask(task_2, 2, 384, 0, 0)
{
    while(1){
        uSetFlagBits(uart1_send, 2) send2, send3);
        uDelay_s(1);
        uSendMsg(uart1_queue, "queue msg 2\r\n");
        uSendMsg(uart1_queue, "queue msg 3\r\n");
        uDelay_s(2);
    }
}

/**
 * \brief    某中断1
 * \details  用来模拟串口1的发送源。
 */
void XXX1_IRQHandler(void) // interrupt XXX1_VECTOR
{
    // 清中断标志位
    iSetFlagBits(uart1_send, 3) send4, send5, send6);
    iSendMsg(uart1_queue, "queue msg 4\r\n");
    iSendMsg(uart1_queue, "queue msg 5\r\n");
    iSendMsg(uart1_queue, "queue msg 6\r\n");
}

/**
 * \brief    某中断2
 * \details  用来模拟串口1的发送源。
 */
void XXX2_IRQHandler(void) // interrupt XXX2_VECTOR
{
    // 清中断标志位
    iGiveSem(uart1_sem); // 并发事件发送
}

/** 启动钩子 */
void start_hook(void)
{
    uart1_recv.err = false;
    uart1_recv.p = uart1_recv.buff;
    HAL_UART_Receive_DMA(&huart1, (uint8_t *)uart1_recv.p, 1);
    uStartTask_Ready(task_1);
    uStartTask_Ready(task_2);
}


#endif
